#![allow(dead_code)]
#![allow(unused_imports)]

use chrono::{DateTime, Duration, Local, NaiveDateTime};
use lazy_static::*;
use std::fs;
use std::fs::read_to_string;
use std::io;
use std::sync::{Arc, Mutex};

use crate::wdlog::log::{DEBUG, ERROR, INFO, PANIC, WARN};
use std::collections::HashMap;

pub type Level = i8;

pub struct LogEntity {
    pub out: Box<dyn io::Write + Send + 'static>,
    pub level: Level,
    pub level_map: HashMap<i8, String>,
    pub prefix: String,   //前缀
    pub print_time: bool, //是否打印时间
    pub file_and_line: bool,
}

impl LogEntity {
    pub fn new() -> LogEntity {
        let mut lp = HashMap::new();
        lp.insert(DEBUG, "DEBUG".to_string());
        lp.insert(INFO, "INFO".to_string());
        lp.insert(WARN, "WARN".to_string());
        lp.insert(ERROR, "ERROR".to_string());
        lp.insert(PANIC, "PANIC".to_string());
        LogEntity {
            out: Box::new(io::stdout()),
            level: DEBUG,
            level_map: lp,
            prefix: "chatroom".to_string(),
            print_time: true,
            file_and_line: true,
        }
    }
}

impl LogEntity {
    pub fn output_file_line(&mut self, l: Level, d: &str, file: &str, line: u32) {
        if self.level < l {
            return;
        }
        let mut ctx = String::new();
        if let Some(s) = self.level_map.get(&l) {
            ctx.push_str(s);
            ctx.push_str("::");
        }
        let prefix = self.prefix.clone();
        if prefix.len() > 0 {
            ctx.push_str(&prefix);
            ctx.push_str("->");
        }
        if self.print_time {
            let t = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
            ctx.push_str(t.as_str());
            ctx.push_str("->");
        }
        if self.file_and_line {
            let line = line.to_string();
            ctx.push_str(file);
            ctx.push_str(":");
            ctx.push_str(&line);
            ctx.push_str("->");
        }
        ctx.push_str(":");
        ctx.push_str(d);
        if let Err(e) = self.out.write_all(ctx.as_bytes()) {
            println!("log out error:{}", e);
        }
        if let Err(e) = self.out.flush() {
            println!("log io error:{}", e);
        }
    }
    pub fn output(&mut self, l: Level, d: &str) {
        if self.level < l {
            return;
        }
        let mut ctx = String::new();
        if let Some(s) = self.level_map.get(&l) {
            ctx.push_str(s);
            ctx.push_str("::");
        }
        let prefix = self.prefix.clone();
        if prefix.len() > 0 {
            ctx.push_str(&prefix);
            ctx.push_str("->");
        }
        if self.print_time {
            let t = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
            ctx.push_str(t.as_str());
            ctx.push_str("->");
        }
        if self.file_and_line {
            let line = line!().to_string();
            let file = file!();
            ctx.push_str(file);
            ctx.push_str(":");
            ctx.push_str(&line);
            ctx.push_str("->");
        }
        ctx.push_str(":");
        ctx.push_str(d);
        if let Err(e) = self.out.write_all(ctx.as_bytes()) {
            println!("log out error:{}", e);
        }
        if let Err(e) = self.out.flush() {
            println!("log io error:{}", e);
        }
    }
    pub fn set_level(&mut self, level: Level) {
        self.level = level;
    }
    pub fn set_prefix(&mut self, prefix: String) {
        self.prefix = prefix;
    }
    pub fn set_time_print(&mut self, ok: bool) {
        self.print_time = ok;
    }
    pub fn set_file_line(&mut self, ok: bool) {
        self.file_and_line = ok;
    }
    pub fn output_to_file(&mut self, path: &str) -> io::Result<()> {
        let mut rfile = fs::File::open(path);
        if let Err(_) = rfile {
            rfile = fs::File::create(path);
        }
        if let Err(e) = rfile {
            return Err(e);
        } else if let Ok(file) = rfile {
            self.out = Box::new(file);
        }
        Ok(())
    }
}
